package dk.flashnotes.fff.tree {	import dk.flashnotes.fff.EMenuXMLKeys;
	import dk.flashnotes.fff.FFFBase;
	import dk.flashnotes.fff.stateHolder.StateHolder;
	import dk.flashnotes.fff.swfaddress.SWFAddressControl;
	import dk.flashnotes.fff.swfaddress.SWFAddressControlEvent;
	import dk.flashnotes.fff.tree.TreeNodeInternalEvent;
	import dk.flashnotes.fff.tree.parameters.NodeParameter;
	import dk.flashnotes.fff.tree.parameters.NodeParameterControl;
	
	import org.osflash.thunderbolt.Logger;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;	
	/**	 * @author josef	 */	public class TreeControl extends EventDispatcher {		private var _xmlFFFTree : XML;		private var _cCustomTreeNodeType : Class;		private var _oRootNode : TreeNode;		private var _oSH : StateHolder;		private var _oSWFAddressControl : SWFAddressControl;		private var _oTNInLine : TreeNode;		private var _oTNCurrent : TreeNode;		private var _bUseSWFAddressRouting : Boolean;		private var _oGlobalNodeParametersControl : NodeParameterControl;		private var _oTNLast : TreeNode;		private var _oTNBlocked : TreeNode;
		private var _bUpdatingFromBrowser : Boolean;
		public function TreeControl() {			super();		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// init tree		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		public function initTreeByXML(xmlFFFTree : XML, bUseSWFAddressRouting : Boolean) : void {			_bUseSWFAddressRouting = bUseSWFAddressRouting;			_xmlFFFTree = xmlFFFTree;						setupGlobalNodeParameterControl();						parseXMLToNodes();			doInitTree();		}		public function startTreeControl() : void {			if (_bUseSWFAddressRouting) {				setupSWFAddress();			} else {				_oRootNode.requestNodeLaunch();			} 						if (FFFBase.get_oInstance().bRemberBlockedNodes) {				setupBlockdNodeHandeling();			}		}		private function doInitTree() : void {						registerRootNode();			registerPageControl();			setupStateHolder();		}				private function registerRootNode() : void {			_oRootNode.addEventListener(TreeNodeInternalEvent.etREQUEST_NODE_LAUNCH_INTERNAL, onNodeRequested, false, 0, true);			_oRootNode.addEventListener(TreeNodeEvent.etPARAMETERS_CHANGED, onNodeParametersChanged, false, 0, true);		}
		private function parseXMLToNodes() : void {			_oRootNode = FFFBase.get_oInstance().oElementFactory.get_oTreeNode(new XML(_xmlFFFTree[EMenuXMLKeys.PAGE]), this);		}		public function get oRootNode() : TreeNode {			return _oRootNode;		}		public function requesetPageFromURL(sURL : String) : void {			var oTN : TreeNode = get_oTNFromUrl(sURL);			if (oTN != null) {				oTN.requestNodeLaunch();			} else {				Logger.warn("No page found for URL :: " + sURL);			}		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// state holder		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function setupStateHolder() : void {						_oSH = new StateHolder(ETreeControlStates.READY, this);			_oSH.registerStateInEventDispatch(ETreeControlStates.READY, new TreeControlEvent(TreeControlEvent.etSET_TO_READY));			_oSH.registerStateInEventDispatch(ETreeControlStates.CHANGING_PAGE, new TreeControlEvent(TreeControlEvent.etSET_CHANGING_PAGE));		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// remember blocked treeNodes		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function setupBlockdNodeHandeling() : void {			if(_bUseSWFAddressRouting) {				_oSWFAddressControl.addEventListener(SWFAddressControlEvent.etURL_CHANGE_BLOCKED, onURLChangedBlockedBySWFAddressControl, false, 0, true);			}			addEventListener(TreeControlEvent.etSET_TO_READY, onTreeControlSetToReady, false, 0, true);		}		private function onTreeControlSetToReady(event : Event) : void {			if(_oTNBlocked) {				requestNodeSelection(_oTNBlocked);				_oTNBlocked = null;			}		}		private function onURLChangedBlockedBySWFAddressControl(event : SWFAddressControlEvent) : void {			set_oTNBlocked(get_oTNFromUrl(event.sURL));		}		private function set_oTNBlocked(oTNBlocked : TreeNode) : void {			_oTNBlocked = oTNBlocked;		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// setup global node parameter handeling		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function setupGlobalNodeParameterControl() : void {			_oGlobalNodeParametersControl = new NodeParameterControl();			//_oGlobalNodeParametersControl.addEventListener(NodeParameterControlEvent.etCHANGED, onNodeParametersChanged, false, 0, true);		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// node parameter handeling		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function onNodeParametersChanged(event : Event) : void {						if (_bUseSWFAddressRouting && !_bUpdatingFromBrowser) {				_oSWFAddressControl.setParameters(get_a_oParameters());			}		}		// returns the global parameters + the parameters from the selected nodes		private function get_a_oParameters() : Array {						var a_oParameters : Array = new Array();						// loop through the selected nodes and retrive the parameters			if(oTNCurrent) {								var oTNTemp : TreeNode = oTNCurrent;				while(oTNTemp.sState == ETreeNodeStates.SELECTED || oTNTemp.sState == ETreeNodeStates.NESTED_SUB_SELECTED) {										for each (var oNP : NodeParameter in oTNTemp.oNodeParameterContol.o_oNPs) {						if(get_bParameterIsUnique(a_oParameters, oNP) && oNP!=null) {							a_oParameters.push(oNP);						}					}					if (!oTNTemp.oParentNode) {						// if on root node with no parent						break;					} else {						oTNTemp = oTNTemp.oParentNode;					}				}			}						// get the global parameters			for each (var oNPGlobal : NodeParameter in _oGlobalNodeParametersControl.o_oNPs) {				if (get_bParameterIsUnique(a_oParameters, oNPGlobal)) {					a_oParameters.push(oNPGlobal);				}			}			return a_oParameters;		}		private function get_bParameterIsUnique(a_oParameters : Array, oNPTest : NodeParameter) : Boolean {			for each (var oNP : NodeParameter in a_oParameters) {				if (oNP.sKey == oNPTest.sKey) {					if(FFFBase.get_oInstance().bTracingEnabled) {						Logger.error("Duplicate parameters!");					}					return false;				}			}			return true;		}		private function onParameterChangedByBrowser(event : SWFAddressControlEvent) : void {						_bUpdatingFromBrowser=true;			_oGlobalNodeParametersControl.lookForUpdate();			_oTNCurrent.oNodeParameterContol.lookForUpdate();			_bUpdatingFromBrowser=false;		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// pagecontrol		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function registerPageControl() : void {			FFFBase.get_oInstance().oPageControl.addEventListener(PageControlEvent.etPAGE_CONTROL_READY, onPageControlReadyAgain, false, 0, true);			FFFBase.get_oInstance().oPageControl.addEventListener(PageControlEvent.etPAGE_CONTROL_BUSY, onPageControlBusy, false, 0, true);		}		private function onPageControlBusy(e : Event) : void {			_oSH.sState = ETreeControlStates.CHANGING_PAGE;		}		private function onPageControlReadyAgain(e : Event) : void {			_oSH.sState = ETreeControlStates.READY;		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// swfaddress		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function setupSWFAddress() : void {			_oSWFAddressControl = new SWFAddressControl(this);			_oSWFAddressControl.addEventListener(SWFAddressControlEvent.etURL_CHANGED, onURLChanged, false, 0, true);			_oSWFAddressControl.addEventListener(SWFAddressControlEvent.etPARAMTER_CHANGED, onParameterChangedByBrowser, false, 0, true);		}				private function onURLChanged(e : Event) : void {			var oTNNew : TreeNode=checkMenuItemOnlyAndRetrunCorrectTN(get_oTNFromUrl(_oSWFAddressControl.sUrl));			if (oTNNew!=null) {				if (oTNNew!=oTNCurrent) {					openPage(oTNNew);				}			}		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// Page request handeling		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function onNodeRequested(e : TreeNodeInternalEvent) : void {			var oTN : TreeNode = e.oTNTarget;			requestNodeSelection(oTN);		}				private function requestNodeSelection(oTN : TreeNode) : void {						if(oTN == _oTNCurrent) {				return;			}						if (!bReadyToChangePage) {				set_oTNBlocked(oTN);			} else {				if (_bUseSWFAddressRouting) {					_oSWFAddressControl.navigateToTreeNode(checkMenuItemOnlyAndRetrunCorrectTN(oTN));				} else {					openPage(checkMenuItemOnlyAndRetrunCorrectTN(oTN));				}			}		}
		
		private function checkMenuItemOnlyAndRetrunCorrectTN(oTN : TreeNode) : TreeNode {			if (!oTN.oTNData.bMenuItemOnly) {				return oTN;			} else {								// hack to allow linking with parms				if (oTN.oTNData.sDefaultSubPageUrl) {					if (oTN.oTNData.sDefaultSubPageUrl.split("?").length>1) {						_oSWFAddressControl.navigateToUrl(oTN.oTNData.sDefaultSubPageUrl.split("?")[0], oTN.oTNData.sDefaultSubPageUrl.split("?")[1]);						return null;						}				}				var _oTNSubToLaunch:TreeNode = oTN.get_oTNSubNodeByURL(oTN.oTNData.sDefaultSubPageUrl);				if (_oTNSubToLaunch!=null) {					return _oTNSubToLaunch;				} else {					if (oTN.a_oSubTreeNodes.length>0) {						return oTN.a_oSubTreeNodes[0];					} else {						return oRootNode;					}				}			}			return null;		}			
		
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// change page		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		private function openPage(oTN : TreeNode) : void {						//			_oTNInLine = oTN;			_oTNLast = _oTNCurrent;			if (_oTNCurrent) {				_oTNCurrent.deSelect();			}			_oTNCurrent = oTN;			dispatchEvent(new TreeControlEvent(TreeControlEvent.etREADY_TO_OPEN_NEW_PAGE));							FFFBase.get_oInstance().oPageControl.openPage(oTN);			oTN.select();			dispatchEvent(new TreeControlEvent(TreeControlEvent.etNEW_TREE_NODE_SELECTED));							updateTreeNodePublicStates();							// set new browser title in url bar			if(_bUseSWFAddressRouting) {				_oSWFAddressControl.setBreadCrumb(get_aSelectedMenuBranchFromSubNode(oTN));			}							// update parameters in url			if (_bUseSWFAddressRouting) {				//_oSWFAddressControl.setParameters(get_a_oParameters(), true);			}		}		public function updateTreeNodePublicStates() : void {						// call for update of TreeNode's public states			dispatchEvent(new TreeControlEvent(TreeControlEvent.etUPDATE_PUBLIC_TREE_STATES));		}				//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// history back/forward		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::				public function stepForward() : void {			SWFAddress.forward();		}		public function stepBack() : void {			SWFAddress.back();		}						//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// find TreeNode		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		public function get_oTNFromUrl(sUrl : String) : TreeNode {						var oTN : TreeNode = searchNode(_oRootNode, sUrl);						// if no TreeNode found in tree (non existing treenode deeplink)			if (!oTN) {				return _oRootNode;			}			return oTN;		}		private function searchNode(oTreeNode : TreeNode, sUrl : String) : TreeNode {						var oTNReturn : TreeNode;						if (oTreeNode.oTNData.sUrl == sUrl) {				oTNReturn = oTreeNode;			}			for each (var oTN : TreeNode in oTreeNode.a_oSubTreeNodes) {				var nTNSub : TreeNode = searchNode(oTN, sUrl);				if (nTNSub) {					oTNReturn = nTNSub;				}			}			return oTNReturn;		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// breadcrumb		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		protected function get_aSelectedMenuBranchFromSubNode(oTN : TreeNode) : Array {						var aReturn : Array = new Array();						while(oTN != _oRootNode) {				aReturn.push(oTN);				var oTNOld : TreeNode = oTN;				oTN = oTNOld.oParentNode;			}									aReturn.push(_oRootNode);			aReturn.reverse();						return aReturn;		}		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		// getters		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::		public function get bReadyToChangePage() : Boolean { 			return _oSH.sState == ETreeControlStates.READY; 		}		public function get oSH() : StateHolder {			return _oSH;		}		public function get oTNCurrent() : TreeNode {			return _oTNCurrent;		}		public function get oGlobalNodeParametersControl() : NodeParameterControl {			return _oGlobalNodeParametersControl;		}		public function get oTNLast() : TreeNode {			return _oTNLast;		}
		public function get oTNInLine() : TreeNode {			return _oTNInLine;
		}		public function get_sParameterString() : String {			var sReturn : String=_oSWFAddressControl.get_sPqrameterString(get_a_oParameters());			if (sReturn!=null) {				return sReturn;			} else {				return "";			}		}
			}}